/*
* This file is a part of the open-eBackup project.
* This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
* If a copy of the MPL was not distributed with this file, You can obtain one at
* http://mozilla.org/MPL/2.0/.
*
* Copyright (c) [2024] Huawei Technologies Co.,Ltd.
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
*/
#ifndef OBJECT_STORAGE_BACKUP_H
#define OBJECT_STORAGE_BACKUP_H

#include <queue>
#include "obs_common/ObjectStorageCommonService.h"
#include "interface/CloudServiceInterface.h"
#include "parser/FileNameListParser.h"

namespace OBSPlugin {
    class ObjectStorageBackupJob : public ObjectStorageCommonService {
    public:
        enum class MONITOR_BACKUP_RES_TYPE {
            MONITOR_BACKUP_RES_TYPE_SUCCESS          = 0,
            MONITOR_BACKUP_RES_TYPE_FAILED           = 1,
            MONITOR_BACKUP_RES_TYPE_ABORTED          = 2,
            MONITOR_BACKUP_RES_TYPE_NEEDRETRY        = 3
        };

        ObjectStorageBackupJob() = default;
        ~ObjectStorageBackupJob() = default;
        EXTER_ATTACK int CheckBackupJobType();
        EXTER_ATTACK int PrerequisiteJob() override;
        EXTER_ATTACK int GenerateSubJob() override;
        EXTER_ATTACK int ExecuteSubJob() override;
        EXTER_ATTACK int PostJob() override;

    private:
        void KeepBackupSubJobAlive(bool &keepAlive);
        bool GetBackupJobInfo();
        int CheckBackupJobTypeInner();
        bool IsFullBackup() const;
        bool GetAuthExtendInfo();
        bool InitJobInfo();
        bool InitCloudClient();
        bool InitObjectStorageInfo();
        std::vector<std::string> DeduplicatePrefixs(const std::vector<std::string>& paths);
        void CloseAggregateSwitchByBackupType();
        bool InitMetaDataCacheBackupFs();
        bool InitRepoPaths();
        bool IsAggregate() const;
        void PrintJobInfo() const;
        bool NeedChangeIncToFull();
        bool GetPrevBackupCopyInfo();
        int PrerequisiteJobInner();
        bool SetupDataFsForBackupJob();
        bool SetupMetaFsForBackupJob();
        int GenerateSubJobInner();
        bool IsMultiNodeBackup() const;
        bool CreateBackupJobTeardownTask();
        bool CreateScanJobTeardownTask();
        int ExecuteSubJobInner();
        int ExecutePrefixScanSubJob(const ObjectStorageBackupSubJob& subJob);
        int GetPrevBackupInfo(const ObjectStorageBackupSubJob& subJob);
        int CopyPreviousMetaFile(
            const std::string& prefixSubStr, const std::string& metaPath, bool& isUnzipping, bool& isSuccess);
        void HoldScanner();
        bool StartScanner(const PrefixInfo& subObject);
        bool FillScanConfig(const PrefixInfo& subObject, ScanConfig& scanConfig);
        void FillScanConfigBasedOnEnviroment(ScanConfig& scanConfig);
        void FillScanConfigBasedOnObsInfo(const PrefixInfo& subObject, ScanConfig& scanConfig);
        bool IsBackupAcl() const;
        void ReportScannerStatus(const ObjectStorageNativeScanStatistics& scanStatistics,
            const AppProtect::SubJobStatus::type& jobStatus, const std::string& jobLogLabel, int jobProgress);
        void ReportScannerCompleteStatus(const ObjectStorageNativeScanStatistics& scanStatistics);
        bool MonitorScanner(const PrefixInfo& subObject, const std::string& esn,
            SubJobStatus::type& jobStatus, std::string& jobLogLabel, int& jobProgress);
        void FillMonitorScannerVarDetails(SCANNER_TASK_STATUS& scanTaskStatus,
            SubJobStatus::type& jobStatus, std::string& jobLogLabel, int& jobProgress);
        void ReportScannerRunningStatus(const ObjectStorageNativeScanStatistics& scanStatistics);
        bool CreateSubTasksFromCtrlFile(const PrefixInfo& prefixInfo, const std::string& esn,
            uint32_t subTaskType);
        bool InitSubJobInfo(const PrefixInfo& prefixInfo, const std::string& ctrlFile,
            const std::string& esn, SubJob &subJob);
        bool CreateBackupCopySubTask(const ObjectStorageBackupSubJob& subJob);
        bool CreateBackupCopyMetaTask(const PrefixInfo& prefixInfo, const std::string& esn);
        int ExecuteDataCopySubJob(ObjectStorageBackupSubJob& subJob);
        bool SkipDeleteStage(const ObjectStorageBackupSubJob& backupSubJob);
        bool UpdateBackupStartTimeInSharedResource(ObjectStorageBackupSubJob& backupSubJob);
        bool StartBackup(const ObjectStorageBackupSubJob& backupSubJob);
        void FillBackupConfig(const ObjectStorageBackupSubJob& backupSubJob, BackupParams& backupParams);
        void FillBackupEngineInfo(const ObjectStorageBackupSubJob& backupSubJob, BackupParams& backupParams);
        void FillBackupConfigPhase(const ObjectStorageBackupSubJob& backupSubJob, BackupParams& backupParams);
        void FillBackupCommonParams(BackupParams& backupParams, const std::string& metaPath);
        void FillAggregateBackupCommonParams(BackupParams& backupParams);
        ObjectStorageBackupJob::MONITOR_BACKUP_RES_TYPE MonitorBackup(BackupStats& backupStatistics,
            SubJobStatus::type& jobStatus, std::string& jobLogLabel, int& jobProgress);
        void HandleMonitorStuck(BackupStats& backupStatistics,
            SubJobStatus::type& jobStatus, std::string& jobLogLabel, int& jobProgress);
        bool UpdateBackupStatistics(BackupStats& backupStatistics);
        bool ReportBackupRunningStatus();
        void HandleMonitorComplete(SubJobStatus::type& jobStatus, std::string& jobLogLabel, int& jobProgress);
        void HandleMonitorFailed(SubJobStatus::type& jobStatus, std::string& jobLogLabel);
        void HandleMonitorAborted(SubJobStatus::type& jobStatus, std::string& jobLogLabel);
        void ReportBackupStatus(const SubJobStatus::type& jobStatus, const std::string& jobLogLabel);

        int ExecuteTeardownSubJob();
        int ExecuteScanTeardownSubJob();
        bool CalculateScanJobStats();
        void FillBackupCopyDetails(ObjectStorageLastCopyDetails& newBackupCopy);
        bool WriteBackupCopyToFile(const std::string& metaFileFullPath, ObjectStorageLastCopyDetails &backupCopy);
        bool CalculateJobStats();
        bool ReportBackupCompletionStatus();

        int ExecuteCopyMetaSubJob(ObjectStorageBackupSubJob& subJob);
        int CopyMetaFileToMetaRepo(const std::string& prefixSubStr, const std::string& metaPath,
            bool& isCopying, bool& isZipSuccess);
        int ExecuteCreateSubJob(const ObjectStorageBackupSubJob& subJob);

        int PostJobInner();
        void RemoveCacheDirectories();
        bool PostReportCopyAdditionalInfo();
        void BuildCopyRepositories(std::vector<StorageRepository>& repositories);
        bool QueryPreviousCopy(Copy& lastCopy);
        bool BuildLastCopyExtendInfo(std::vector<BackupObjectInfo> &backupObjectInfo);
        bool ListBucketPrefixs(std::vector<PrefixInfo>& bucketPrefix);
        bool ListBucketObjectsByDepth(const std::string& bucketName, std::string& prefix,
            PrefixInfo& prefixInfo);
        bool LevelListObject(const std::string& bucketName, int level,
            std::deque<std::string>& levelPrefixQueue, PrefixInfo& prefixInfo);
        bool StartListPrefix();
        int CreateSubJobFromBackupObjectInfo(const std::vector<BackupObjectInfo>& backupObjectInfos);
        bool CreateSubJobForMutiNodeBackup();
        bool WriteBackupObjectInfoToFile(BackupObjectInfosInCopy& backupObjectInfos);
        int SwitchStorageForMutiNodeBackup(const ObjectStorageBackupSubJob& backupSubJob);
        bool CheckSubJobNeedSwitchStorage(const std::string& esn, const StorageGeneralInfo& storageGeneralInfo);
        bool CheckAndGetObjectInfo(const std::string& esn, StorageGeneralInfo& storageGeneralInfo,
            BackupObjectInfosInCopy& backupObjectInfosInCopy);
        bool ReallocateSubJob(ObjectStorageBackupSubJob& backupSubJob,
            BackupObjectInfosInCopy& backupObjectInfosInCopy);
        bool CreateStorageGeneralResources(const std::string& jobId, StorageGeneralInfo& generalInfo);
        bool GetStorageGeneralResources(const std::string& jobId, StorageGeneralInfo& generalInfo);
        bool UpdateStorageGeneralResources(const std::string& jobId, StorageGeneralInfo& generalInfo);
        bool DeleteStorageGeneralResources(const std::string& jobId);
        bool LockStorageGeneralResources(const std::string& jobId);
        bool UnLockStorageGeneralResources(const std::string& jobId);
        bool IsContinueOnNodeFailed();
        std::string GetStorageStatusExtend(int64_t errCode);
        bool InitRepoPathsByEsn(const std::vector<StorageRepository>& multiFsList,
            std::unordered_map<std::string, std::string>& fsPathMap);
        bool ClearStatusBeforeSwitch();
        bool UpdateScanStatInfo(const PrefixInfo& prefixInfo, ObjectStorageNativeScanStatistics& scanStatistics);
        bool ReportScanRunningStatus();
        bool NeedContinueCheckpoint();
        int32_t CopyLastUncompleteBackupData(std::string metaPath);
        bool findFilesInCachePath(std::vector<std::string>& fileList);
        bool DeleteControlCheckpointFile(ObjectStorageBackupSubJob& subJob);
        bool CreateControlCheckpointFile(ObjectStorageBackupSubJob& subJob);
        int RecordErrInfo(uint32_t number);
        bool ReadFromCache();
        bool WriteToCache(ObjectStorageCheckPointRecord& checkRecord);
        bool ScanPrefix(const ObjectStorageBackupSubJob& subJob, SubJobStatus::type& jobStatus,
            std::string& jobLogLabel, int& jobProgress);

        // log inc backup
        bool IsBucketLogInc() const;
        bool GetBucketLogs();
        bool FullBackupUpdateGeneralInfo();
        std::string GetCurrentTimeStamp();
        bool RetrieveFullLogStamp();
        bool PrepareBucketLog(const std::string& bucketName, const std::string& bucketLogDownloadDir);
        bool SetBucketLogTimestamp(const std::string &bucketName, const std::string &logTimeStamp);
        bool DownloadAllBucketLog(
            const std::string& bucketName,
            const std::string& targetBucketName,
            const std::string& targetPrefix,
            const std::string& bucketLogDownloadDir,
            const std::unique_ptr<Module::FileNameListParser>& fileNameListParser);
        bool DownloadOneBucketLog(
            const std::string& bucketName,
            const std::string& targetBucketName,
            const std::string& key,
            const std::string& logFilePath);
        bool ParseBucketLog(const OBSProtectSubObject& object);
        std::string FindParentPrefix(const PrefixInfo& prefixInfo);
        void ReportJobDetailsWithDetailAndErrcode(
            const std::tuple<JobLogLevel::type, SubJobStatus::type, const int> &reportInfo,
            const std::string& logLabel, const int64_t errCode, const std::string& message);

        bool CheckIsExistEsn(const std::string& esn, const std::vector<BackupObjectInfo>& objectInfos);
        bool SetRepoAbnormalFlag(const std::vector<BackupObjectInfo>& objectInfos,
            std::vector<StorageRepository>& repositories);
        void ReportSwitchLabel(ObjectStorageBackupSubJob& backupSubJob, const std::string& abnormalEsn);
        bool IsProtectedObjectsChanged();
        bool IsPrefixsChanged(OBSProtectSubObject& curObject, OBSProtectSubObject& preObject);
        bool IsAclTypeChanged();
        bool IsMultiNodeBackupSwitchChanged();
        void SortProtectSubObjectList(std::vector<OBSProtectSubObject>& protectSubObjectList);
        void ReportAverageSpeed();
        bool CreateBackupJobTaskToCreateFurtherSubTasks(const ObjectStorageBackupSubJob& subJob);
        bool GetCheckPointRecord();
        int ExecuteSkipScanSubJob(const ObjectStorageBackupSubJob& subJob);
        bool GetCtrlFile(std::string srcDir, std::string dstDir, std::vector<std::string>& srcFileList,
            const PrefixInfo& prefixInfo);
        void ChangeJobStatus(SubJobStatus::type jobStatus, ObjectStorageBackupSubJob& subJob);
        std::unique_ptr<Module::CloudServiceInterface> m_cloudClient {};
        BackupObjectInfosInCopy m_backupObjectCopyInfo;
        void QueryScannerStatus();
        void GetBackupFailDetails();
        bool findFileInMetaPath(std::vector<std::string>& metaPreFixList, const PrefixInfo& prefixInfo);
        void RecordMetaPerfix(ObjectStorageBackupSubJob& subJob);

        std::shared_ptr<AppProtect::BackupJob> m_backupJobPtr {};
        ProtectedOBS m_protectedOBS;
        /* JSON file (/m_metaFs/backup-copy-meta.json) where the meta info about the backup copy is stored */
        std::string m_backupCopyInfoFilePath;
        /* Pre backup copy info genereted in last job */
        ObjectStorageLastCopyDetails m_prevBackupRecord {};
        time_t m_lastBackupTime { 0 };
        /* RequestId for mainJob and subJob */
        size_t m_mainJobRequestId { 0 };
        size_t m_subJobRequestId { 0 };
        int64_t m_lastScannerReportTime {};
        /* Secondary Storage dataFS Info */
        std::vector<StorageRepository> m_multiDataFsList;
        std::unordered_map<std::string, std::string> m_dataFsPathMap;
        std::vector<StorageRepository> m_multiMetaFsList;
        std::unordered_map<std::string, std::string> m_metaFsPathMap;
        /* Secondary Storage metaFS Info */
        StorageRepository m_metaFs;
        std::string m_metaFsPath;
        /* Secondary Storage cacheFs Info */
        StorageRepository m_cacheFs;
        std::string m_cacheFsPath;
        std::string m_statisticsPath;
        std::string m_scanStatisticsPath;
        std::string m_scanMetaPath;
        std::string m_scanControlPath;
        std::string m_backupControlPath;
        std::string m_backupObjectInfoFilePath;
        std::string m_bucketLogDir;
        std::string m_objectListDir;
        /* Backup instance */
        std::unique_ptr<FS_Backup::Backup> m_backup {};
        BackupPhaseStatus m_backupStatus;
        /* General info about backup job - saved in SharedResource */
        ObjectStorageNativeGeneral m_generalInfo {};
        /* Scanner statistics - saved in SharedResource */
        ObjectStorageNativeScanStatistics m_scanStats {};
        /* Backup statistics - saved in SharedResource */
        ObjectStorageNativeBackupStats m_backupStats {};
        /* Used for reporting job progress log to agent */
        ActionResult m_logResult {};
        SubJobDetails m_logSubJobDetails {};
        LogDetail m_logDetail{};
        std::vector<LogDetail> m_logDetailList;
        ErrRecorder m_scanError;

        std::atomic<bool> m_isCopying { false };
        std::atomic<bool> m_isZipSuccess { false };

        uint32_t m_numberOfSubTask = 0;
        std::string m_checkPath;
        std::string m_subCheckPath;
        std::string m_subCheckMetaPath;
        ObjectStorageCheckPointRecord m_checkPointRecord;
        std::vector<PrefixInfo> m_bucketPrefixList; // 分层遍历桶前缀结果
        std::atomic<bool> m_isListPrefixFinish { false };
        int m_isCompressMeta = 0; // 是否压缩元数据：0-不压缩，其他压缩
        std::string m_backErrMsg;
        std::unordered_map<std::string, std::vector<std::string>> m_bucketPrefixMap;  // key: <endpoint,buckets>
        bool m_encodeSwitch = false;
    };
}

#endif
